# -*- codeing = utf-8 -*-
# !/usr/bin/env python
# @coding  : utf-8
# @File    : t1.py
# @Time    : 2022/5/27 20:12
# @Author  : xdd
# @Software: PyCharm
# @desc :$

import random
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


#
def calcDis(dataSet, centroids, k):
    """
    计算欧拉距离
    :param dataSet:  数据集
    :param centroids: 质心
    :param k: 划分的数量
    :return:返回一个每个点到质点的距离len(dateSet)*k的数组
    """
    clalist = []
    for data in dataSet:
        diff = np.tile(data, (k,1)) - centroids  # 相减   (np.tile(a,(2,1))就是把a先沿x轴复制1倍，即没有复制，仍然是 [0,1,2]。 再把结果沿y方向复制2倍得到array([[0,1,2],[0,1,2]]))
        squaredDiff = diff ** 2  # 平方
        squaredDist = np.sum(squaredDiff, axis=1)  # 和  (axis=1表示行)
        distance = squaredDist ** 0.5  # 开根号
        clalist.append(distance)
    clalist = np.array(clalist)  # 返回一个每个点到质点的距离len(dateSet)*k的数组
    return clalist


#
def classify(dataSet, centroids, k):
    """
    计算质心
    :param dataSet:  数据集
    :param centroids: 质心
    :param k: 划分的数量
    :return:
    """
    # 计算样本到质心的距离
    clalist = calcDis(dataSet, centroids, k)
    # 分组并计算新的质心
    minDistIndices = np.argmin(clalist, axis=1)  # axis=1 表示求出每行的最小值的下标
    newCentroids = pd.DataFrame(dataSet).groupby(
        minDistIndices).mean()  # DataFramte(dataSet)对DataSet分组，groupby(min)按照min进行统计分类，mean()对分类结果求均值
    newCentroids = newCentroids.values

    # 计算变化量
    changed = newCentroids - centroids

    return changed, newCentroids


#
def kmeans(dataSet, k):
    """
    使用k-means分类


    :param dataSet: 数据集
    :param k: 分类数量
    :return:centroids质心
    cluster集群
    """
    # 随机取质心
    centroids = random.sample(dataSet, k)

    # 更新质心 直到变化量全为0
    changed, newCentroids = classify(dataSet, centroids, k)
    while np.any(changed != 0):
        changed, newCentroids = classify(dataSet, newCentroids, k)

    centroids = sorted(newCentroids.tolist())  # tolist()将矩阵转换成列表 sorted()排序

    # 根据质心计算每个集群
    cluster = []
    clalist = calcDis(dataSet, centroids, k)  # 调用欧拉距离
    minDistIndices = np.argmin(clalist, axis=1)
    for i in range(k):
        cluster.append([])
    for i, j in enumerate(minDistIndices):  # enymerate()可同时遍历索引和遍历元素
        cluster[j].append(dataSet[i])

    return centroids, cluster




def createDataSet(test):
    """
    创建数据集
     """
    # arr =np.random.randint(100, size=(100, 1, 2))[:, 0, :]
    # list_arr =list(arr)
    list_arr=[[56, 95], [29, 91], [40, 56], [8, 80], [53, 65], [56, 79], [43, 70],
  [61, 92], [15, 10], [53, 98], [9, 74], [4, 66], [9, 22], [25, 98],
  [25, 0], [12, 29], [32, 81], [3, 79], [0, 64], [9, 21], [23, 58],
  [38, 31], [27, 41], [48, 95], [42, 63], [43, 90], [13, 51],
  [30, 92], [33, 69], [1, 27], [38, 59], [27, 93], [50, 68], [39, 93],
  [10, 36], [2, 64], [1, 80], [24, 18], [32, 60], [24, 41], [8, 51],
  [23, 57], [13, 18], [34, 12], [13, 3], [37, 40], [0, 93], [10, 22],
  [42, 67], [31, 87], [20, 28], [48, 73],
  [87, 26], [50, 37], [64, 83], [79, 51], [86, 77], [93, 17], [51, 47],
  [81, 47], [69, 46], [38, 12], [96, 44], [66, 48], [86, 23], [68, 48],
  [70, 93], [40, 19], [84, 75], [82, 37], [65, 57], [49, 34], [91, 69],
  [65, 21], [91, 58], [47, 14], [48, 40], [87, 88], [80, 90], [74, 41],
  [93, 3], [58, 33], [97, 72], [73, 28], [84, 47], [63, 7], [78, 91],
  [83, 13], [94, 64], [85, 82], [67, 26], [76, 9], [72, 88], [68, 76],
  [52, 7], [63, 4], [55, 49], [84, 2], [60, 19]]
    return list_arr
    # return [[1, 1], [1, 2], [2, 1], [6, 4], [6, 3], [5, 4]]


if __name__ == '__main__':
    dataset = createDataSet(0)
    centroids, cluster = kmeans(dataset, 3)

    # 显示数据
    col = ['HotPink', 'Aqua', 'Chartreuse', 'yellow', 'LightSalmon']
    coler_idx=0;
    for arr in cluster:
        for i in range(len(arr)):
            plt.scatter(arr[i][0], arr[i][1], marker='o', color=col[coler_idx], s=40, label='原始点')
        coler_idx+=1;
                 #  记号形状       颜色      点的大小      设置标签
     # for i in range(len(cluster)):

    # 显示质心
    for j in range(len(centroids)):

        plt.scatter(centroids[j][0], centroids[j][1], marker='x', color='red', s=50, label='质心')

    plt.show()

